package com.yunti.springboot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunti.springboot.bo.UserBO;
import com.yunti.springboot.config.component.AbstractCurrentRequestComponent;
import com.yunti.springboot.job.constant.ScheduleConstants;
import com.yunti.springboot.job.exception.TaskException;
import com.yunti.springboot.job.util.ScheduleUtils;
import com.yunti.springboot.mapper.TaskJobMapper;
import com.yunti.springboot.po.TaskJob;
import com.yunti.springboot.service.TaskJobService;
import com.yunti.springboot.vo.Result;
import com.yunti.springboot.vo.req.TaskJobReq;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 定时任务调度表 服务实现类
 * </p>
 *
 * @author ytt
 * @since 2023-07-06
 */
@Service
public class TaskJobServiceImpl extends ServiceImpl<TaskJobMapper, TaskJob> implements TaskJobService {
    @Resource
    TaskJobMapper mapper;
    @Resource
    private AbstractCurrentRequestComponent abstractCurrentRequestComponent;
    @Resource
    private Scheduler scheduler;
    /**
     * 项目启动时，初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）
     */
    @PostConstruct
    public void init() throws SchedulerException, TaskException
    {
        scheduler.clear();
        LambdaQueryWrapper<TaskJob>queryWrapper =  new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskJob::getStatus, ScheduleConstants.Status.NORMAL.getValue());
        List<TaskJob> jobList = mapper.selectList(queryWrapper);
        for (TaskJob job : jobList)
        {
            ScheduleUtils.createScheduleJob(scheduler, job);
        }
    }

    @Override
    public Result getList(TaskJobReq req) {
        LambdaQueryWrapper<TaskJob> queryWrapper = new LambdaQueryWrapper<>();
        if (req.getCurrent() == null) {
            req.setCurrent(0);
        }
        if (req.getSize() == null) {
            req.setSize(10);
        }
        if (req.getJobId() != null) {
            queryWrapper.eq(TaskJob::getJobId, req.getJobId());
        }
        if (StrUtil.isNotBlank(req.getJobName())) {
            queryWrapper.like(TaskJob::getJobName, req.getJobName());
        }
        if (req.getStatus() != null) {
            queryWrapper.eq(TaskJob::getStatus, req.getStatus());
        }
        if (req.getJobGroup() != null) {
            queryWrapper.eq(TaskJob::getJobGroup, req.getJobGroup());
        }
        Page page = new Page<>(req.getCurrent(), req.getSize());
        return Result.success(mapper.selectPage(page, queryWrapper));
    }

    @Override
    public Result del(TaskJobReq req) {
        if (req.getJobId() == null) {
            return Result.error("id 不能为null");
        }
        if (mapper.deleteById(req.getJobId()) > 0) {
            try {
                deleteJob(req);
            } catch (SchedulerException e) {
                e.printStackTrace();
                return Result.error("删除失败！");
            }
            return Result.success("删除成功！");
        } else {
            return Result.error("删除失败！");
        }
    }

    @Override
    public Result add(TaskJobReq req) {
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        TaskJob task = new TaskJob();
        BeanUtil.copyProperties(req, task);
        task.setJobId(null);
        task.setCreateTime(LocalDateTime.now());
        task.setCreateBy(userBO.getUsername());
        if (mapper.insert(task) > 0) {
            try {
                task.setStatus(ScheduleConstants.Status.PAUSE.getValue());
                ScheduleUtils.createScheduleJob(scheduler, task);
            } catch (SchedulerException e) {
                e.printStackTrace();
            } catch (TaskException e) {
                e.printStackTrace();
            }
            return Result.success("新增成功！");
        }

        return Result.error("新增失败！");
    }

    @Override
    public Result edit(TaskJobReq req) {
        if (req.getJobId() == null) {
            return Result.error("更改失败！id不存在");
        }
        UserBO userBO = abstractCurrentRequestComponent.getCurrentStaffId();
        TaskJob task = new TaskJob();
        BeanUtil.copyProperties(req, task);
        task.setUpdateTime(LocalDateTime.now());
        task.setCreateBy(userBO.getUsername());
        if (mapper.updateById(task) > 0){
            try {
                updateSchedulerJob(task,task.getJobGroup());
            } catch (SchedulerException | TaskException e) {
                e.printStackTrace();
            }
            return Result.success("更改成功！");
        }

        return Result.error("更改失败！");
    }

    @Override
    public Result run(TaskJobReq job) {
        boolean result = false;
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        TaskJob properties = mapper.selectById(job.getJobId());
        // 参数
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
        try {
            if (scheduler.checkExists(jobKey)) {
                result = true;
                scheduler.triggerJob(jobKey, dataMap);
            }
        } catch (SchedulerException e) {
            result = false;
            e.printStackTrace();
        }
        if (result) {
            return Result.success("启动成功！");
        }
        return Result.error("启动失败！");
    }

    @Override
    public Result change(TaskJobReq job) {
        String status = job.getStatus();
        int rows = 0;
        if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) {
            try {
                rows = resumeJob(job);
            } catch (SchedulerException e) {
                e.printStackTrace();
                return Result.error("更改失败！");
            }
        } else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) {
            try {
                rows = pauseJob(job);
            } catch (SchedulerException e) {
                e.printStackTrace();
                return Result.error("更改失败！");
            }
        }
        if (rows > 0) {
            return Result.success("更改成功！");
        }
        return Result.error("更改失败！");
    }


    /**
     * 暂停任务
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int pauseJob(TaskJobReq job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        TaskJob taskJob = new TaskJob();
        BeanUtil.copyProperties(job, taskJob);
        taskJob.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        int rows = mapper.updateById(taskJob);
        if (rows > 0) {
            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }

    /**
     * 恢复任务
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int resumeJob(TaskJobReq job) throws SchedulerException {
        Long jobId = job.getJobId();
        TaskJob taskJob = new TaskJob();
        BeanUtil.copyProperties(job, taskJob);
        String jobGroup = job.getJobGroup();
        taskJob.setStatus(ScheduleConstants.Status.NORMAL.getValue());
        int rows = mapper.updateById(taskJob);
        if (rows > 0) {
            scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }

    /**
     * 删除任务后，所对应的trigger也将被删除
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteJob(TaskJobReq job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        int rows = mapper.deleteById(jobId);
        if (rows > 0) {
            scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }

    /**
     * 更新任务
     *
     * @param job 任务对象
     * @param jobGroup 任务组名
     */
    public void updateSchedulerJob(TaskJob job, String jobGroup) throws SchedulerException, TaskException
    {
        Long jobId = job.getJobId();
        // 判断是否存在
        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
        if (scheduler.checkExists(jobKey))
        {
            // 防止创建时存在数据问题 先移除，然后在执行创建操作
            scheduler.deleteJob(jobKey);
        }
        ScheduleUtils.createScheduleJob(scheduler, job);
    }

}
